, SYM_POST_INCREMENT, SYM_POST_DECREMENT // Kept in this position for use by YIELDS_AN_OPERAND() [helps performance].
, SYM_CPAREN, SYM_OPAREN, SYM_COMMA // CPAREN (close-paren) must come right before OPAREN and must be the first non-operand symbol other than SYM_BEGIN.
#define YIELDS_AN_OPERAND(symbol) ((symbol) < SYM_OPAREN) // CPAREN also covers the tail end of a function call. Post-inc/dec yields an operand for things like Var++ + 2. Definitely needs the parentheses around symbol.
, SYM_ASSIGN_CONCAT // THIS MUST BE KEPT AS THE LAST (AND SYM_ASSIGN THE FIRST) BECAUSE THEY'RE USED IN A RANGE-CHECK.
#define IS_ASSIGNMENT_EXCEPT_POST_AND_PRE(symbol) (symbol <= SYM_ASSIGN_CONCAT && symbol >= SYM_ASSIGN) // Check upper bound first for short-circuit performance.
#define IS_ASSIGNMENT_OR_POST_OP(symbol) (IS_ASSIGNMENT_EXCEPT_POST_AND_PRE(symbol) || symbol == SYM_POST_INCREMENT || symbol == SYM_POST_DECREMENT)
, SYM_IFF_ELSE, SYM_IFF_THEN // THESE TERNARY OPERATORS MUST BE KEPT IN THIS ORDER AND ADJACENT TO THE BELOW.
, SYM_OR, SYM_AND // MUST BE KEPT IN THIS ORDER AND ADJACENT TO THE ABOVE because infix-to-postfix is optimized to check a range rather than a series of equalities.
, SYM_LOWNOT // LOWNOT is the word "not", the low precedence counterpart of !
, SYM_EQUAL, SYM_EQUALCASE, SYM_NOTEQUAL // =, ==, <> ... Keep this in sync with IS_RELATIONAL_OPERATOR() below.
, SYM_GT, SYM_LT, SYM_GTOE, SYM_LTOE // >, <, >=, <= ... Keep this in sync with IS_RELATIONAL_OPERATOR() below.
#define IS_RELATIONAL_OPERATOR(symbol) (symbol >= SYM_EQUAL && symbol <= SYM_LTOE)
, SYM_CONCAT
, SYM_BITOR // Seems more intuitive to have these higher in prec. than the above, unlike C and Perl, but like Python.
, SYM_BITXOR // SYM_BITOR (ABOVE) MUST BE KEPT FIRST AMONG THE BIT OPERATORS BECAUSE IT'S USED IN A RANGE-CHECK.
, SYM_BITAND
, SYM_BITSHIFTLEFT, SYM_BITSHIFTRIGHT // << >> ALSO: SYM_BITSHIFTRIGHT MUST BE KEPT LAST AMONG THE BIT OPERATORS BECAUSE IT'S USED IN A RANGE-CHECK.
, SYM_ADD, SYM_SUBTRACT
, SYM_MULTIPLY, SYM_DIVIDE, SYM_FLOORDIVIDE
, SYM_NEGATIVE, SYM_HIGHNOT, SYM_BITNOT, SYM_ADDRESS, SYM_DEREF // Don't change position or order of these because Infix-to-postfix converter's special handling for SYM_POWER relies on them being adjacent to each other.
, SYM_POWER // See comments near precedence array for why this takes precedence over SYM_NEGATIVE.
, SYM_PRE_INCREMENT, SYM_PRE_DECREMENT // Must be kept after the post-ops and in this order relative to each other due to a range check in the code.
, SYM_FUNC // A call to a function.
, SYM_COUNT // Must be last because it's the total symbol count for everything above.
, SYM_INVALID = SYM_COUNT // Some callers may rely on YIELDS_AN_OPERAND(SYM_INVALID)==false.
};
// These two are macros for maintainability (i.e. seeing them together here helps maintain them together).
#define SYM_DYNAMIC_IS_DOUBLE_DEREF(token) (token.buf) // SYM_DYNAMICs other than doubles have NULL buf, at least at the stage this macro is called.
#define SYM_DYNAMIC_IS_VAR_NORMAL_OR_CLIP(token) (!(token)->buf && ((token)->var->Type() == VAR_NORMAL || (token)->var->Type() == VAR_CLIPBOARD)) // i.e. it's an evironment variable or the clipboard, not a built-in variable or double-deref.
struct DerefType; // Forward declarations for use below.
class Var; //
struct ExprTokenType // Something in the compiler hates the name TokenType, so using a different name.
{
// Due to the presence of 8-byte members (double and __int64) this entire struct is aligned on 8-byte
// vs. 4-byte boundaries. The compiler defaults to this because otherwise an 8-byte member might
// sometimes not start at an even address, which would hurt performance on Pentiums, etc.
union // Which of its members is used depends on the value of symbol, below.
{
__int64 value_int64; // for SYM_INTEGER
double value_double; // for SYM_FLOAT
struct
{
union // These nested structs and unions minimize the token size by overlapping data.
{
DerefType *deref; // for SYM_FUNC
Var *var; // for SYM_VAR
char *marker; // for SYM_STRING and SYM_OPERAND.
};
char *buf; // This doesn't increase the total size of the struct. It's used by built-in functions and perhaps other misc. purposes.
};
};
// Note that marker's str-length should not be stored in this struct, even though it might be readily
// available in places and thus help performance. This is because if it were stored and the marker
// or SYM_VAR's var pointed to a location that was changed as a side effect of an expression's
// call to a script function, the length would then be invalid.
SymbolType symbol; // Short-circuit benchmark is currently much faster with this and the next beneath the union, perhaps due to CPU optimizations for 8-byte alignment.
// MsgBox timeout value. This can't be zero because that is used as a failure indicator:
// Also, this define is in this file to prevent problems with mutual
// dependency between script.h and window.h. Update: It can't be -1 either because
// that value is used to indicate failure by DialogBox():
#define AHK_TIMEOUT -2
// And these to prevent mutual dependency problem between window.h and globaldata.h:
#define MAX_MSGBOXES 7
#define MAX_INPUTBOXES 4
#define MAX_PROGRESS_WINDOWS 10 // Allow a lot for downloads and such.
#define MAX_PROGRESS_WINDOWS_STR "10" // Keep this in sync with above.
#define MAX_SPLASHIMAGE_WINDOWS 10
#define MAX_SPLASHIMAGE_WINDOWS_STR "10" // Keep this in sync with above.
#define MAX_GUI_WINDOWS 99 // Things that parse the "NN:" prefix for Gui/GuiControl might rely on this being 2-digit.
#define MAX_GUI_WINDOWS_STR "99" // Keep this in sync with above.
#define MAX_MSG_MONITORS 500
// IMPORTANT: Before ever changing the below, note that it will impact the IDs of menu items created
// with the MENU command, as well as the number of such menu items that are possible (currently about
// 65500-11000=54500). See comments at ID_USER_FIRST for details:
#define GUI_CONTROL_BLOCK_SIZE 1000
#define MAX_CONTROLS_PER_GUI (GUI_CONTROL_BLOCK_SIZE * 11) // Some things rely on this being less than 0xFFFF and an even multiple of GUI_CONTROL_BLOCK_SIZE.
#define NO_CONTROL_INDEX MAX_CONTROLS_PER_GUI // Must be 0xFFFF or less.
#define NO_EVENT_INFO 0 // For backward compatibility with documented contents of A_EventInfo, this should be kept as 0 vs. something more special like UINT_MAX.
#define MAX_TOOLTIPS 20
#define MAX_TOOLTIPS_STR "20" // Keep this in sync with above.
#define MAX_FILEDIALOGS 4
#define MAX_FOLDERDIALOGS 4
#define MAX_NUMBER_LENGTH 20
#define MAX_NUMBER_SIZE (MAX_NUMBER_LENGTH + 1)
// Above is the maximum length of a 64-bit number when expressed as decimal or hex string.
// e.g. -9223372036854775808 or (unsigned) 18446744073709551616
// Hot-strings:
// memmove() and proper detection of long hotstrings rely on buf being at least this large:
// MsgSleep() is used rather than SLEEP_WITHOUT_INTERRUPTION to allow other hotkeys to
// launch and interrupt (suspend) the operation. It seems best to allow that, since
// the user may want to press some fast window activation hotkeys, for example, during
// the operation. The operation will be resumed after the interrupting subroutine finishes.
// Notes applying to the macro:
// Store tick_now for use later, in case the Peek() isn't done, though not all callers need it later.
// ...
// Since the Peek() will yield when there are no messages, it will often take 20ms or more to return
// (UPDATE: this can't be reproduced with simple tests, so either the OS has changed through service
// packs, or Peek() yields only when the OS detects that the app is calling it too often or calling
// it in certain ways [PM_REMOVE vs. PM_NOREMOVE seems to make no differnce: either way it doesn't yield]).
// Therefore, must update tick_now again (its value is used by macro and possibly by its caller)
// to avoid having to Peek() immediately after the next iteration.
// ...
// The code might bench faster when "g_script.mLastPeekTime = tick_now" is a separate operation rather
// than combined in a chained assignment statement.
#define LONG_OPERATION_UPDATE \
{\
tick_now = GetTickCount();\
if (tick_now - g_script.mLastPeekTime > g.PeekFrequency)\
{\
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))\
MsgSleep(-1);\
tick_now = GetTickCount();\
g_script.mLastPeekTime = tick_now;\
}\
}
// Same as the above except for SendKeys() and related functions (uses SLEEP_WITHOUT_INTERRUPTION vs. MsgSleep).
#define LONG_OPERATION_UPDATE_FOR_SENDKEYS \
{\
tick_now = GetTickCount();\
if (tick_now - g_script.mLastPeekTime > g.PeekFrequency)\
{\
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))\
SLEEP_WITHOUT_INTERRUPTION(-1) \
tick_now = GetTickCount();\
g_script.mLastPeekTime = tick_now;\
}\
}
// Defining these here avoids awkwardness due to the fact that globaldata.cpp
// does not (for design reasons) include globaldata.h:
typedef UCHAR ActionTypeType; // If ever have more than 256 actions, will have to change this (but it would increase code size due to static data in g_act).
#pragma pack(1) // v1.0.45: Reduces code size a little without impacting runtime performance because this struct is hardly ever accessed during runtime.
struct Action
{
char *Name;
// Just make them int's, rather than something smaller, because the collection
// of actions will take up very little memory. Int's are probably faster
// for the processor to access since they are the native word size, or something:
// Update for v1.0.40.02: Now that the ARGn macros don't check mArgc, MaxParamsAu2WithHighBit
// is needed to allow MaxParams to stay pure, which in turn prevents Line::Perform()
// from accessing a NULL arg in the sArgDeref array (i.e. an arg that exists only for
// non-AutoIt2 scripts, such as the extra ones in StringGetPos).
// Also, changing these from ints to chars greatly reduces code size since this struct
// is used by g_act to build static data into the code. Testing shows that the compiler
// will generate a warning even when not in debug mode in the unlikely event that a constant
// larger than 127 is ever stored in one of these:
// Array indicating which args must be purely numeric. The first arg is
// number 1, the second 2, etc (i.e. it doesn't start at zero). The list
// is ended with a zero, much like a string. The compiler will notify us
// (verified) if MAX_NUMERIC_PARAMS ever needs to be increased:
#define MAX_NUMERIC_PARAMS 7
ActionTypeType NumericParams[MAX_NUMERIC_PARAMS];
};
#pragma pack() // Calling pack with no arguments restores the default value (which is 8, but "the alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.")
// Values are hard-coded for some of the below because they must not deviate from the documented, numerical
enum GuiEventTypes {GUI_EVENT_NONE // NONE must be zero for any uses of ZeroMemory(), synonymous with false, etc.
, GUI_EVENT_NORMAL, GUI_EVENT_DBLCLK // Try to avoid changing this and the other common ones in case anyone automates a script via SendMessage (though that does seem very unlikely).
, GUI_EVENT_RCLK, GUI_EVENT_COLCLK
, GUI_EVENT_FIRST_UNNAMED // This item must always be 1 greater than the last item that has a name in the GUI_EVENT_NAMES array below.
, GUI_EVENT_DIGIT_0 = 48}; // Here just as a reminder that this value and higher are reserved so that a single printable character or digit (mnemonic) can be sent, and also so that ListView's "I" notification can add extra data into the high-byte (which lies just to the left of the "I" character in the bitfield).
// Bitwise flags:
typedef UCHAR CoordModeAttribType;
#define COORD_MODE_PIXEL 0x01
#define COORD_MODE_MOUSE 0x02
#define COORD_MODE_TOOLTIP 0x04
#define COORD_MODE_CARET 0x08
#define COORD_MODE_MENU 0x10
#define COORD_CENTERED (INT_MIN + 1)
#define COORD_UNSPECIFIED INT_MIN
#define COORD_UNSPECIFIED_SHORT SHRT_MIN // This essentially makes coord -32768 "reserved", but it seems acceptable given usefulness and the rarity of a real coord like that.
// Same reason as above struct. It's best to keep this struct as small as possible
// because it's used as a local (stack) var by at least one recursive function:
// Each instance of this struct generally corresponds to a quasi-thread. The function that creates
// a new thread typically saves the old thread's struct values on its stack so that they can later
// be copied back into the g struct when the thread is resumed:
class Func; // Forward declarations
class Label; //
struct RegItemStruct; //
struct LoopReadFileStruct; //
struct global_struct
{
// 8-byte items are listed first, which might improve alignment for 64-bit processors (dubious).
__int64 LinesPerCycle; // Use 64-bits for this so that user can specify really large values.
__int64 mLoopIteration; // Signed, since script/ITOA64 aren't designed to handle unsigned.
WIN32_FIND_DATA *mLoopFile; // The file of the current file-loop, if applicable.
RegItemStruct *mLoopRegItem; // The registry subkey or value of the current registry enumeration loop.
LoopReadFileStruct *mLoopReadFile; // The file whose contents are currently being read by a File-Read Loop.
char *mLoopField; // The field of the current string-parsing loop.
// v1.0.44.14: The above mLoop attributes were moved into this structure from the script class
// because they're more approriate as thread-attributes rather than being global to the entire script.
TitleMatchModes TitleMatchMode;
int IntervalBeforeRest;
int UninterruptedLineCount; // Stored as a g-struct attribute in case OnExit sub interrupts it while uninterruptible.
int Priority; // This thread's priority relative to others.
DWORD LastError; // The result of GetLastError() after the most recent DllCall or Run.
GuiEventType GuiEvent; // This thread's triggering event, e.g. DblClk vs. normal click.
DWORD EventInfo; // Not named "GuiEventInfo" because it applies to non-GUI events such as clipboard.
POINT GuiPoint; // The position of GuiEvent. Stored as a thread vs. window attribute so that underlying threads see their original values when resumed.
GuiIndexType GuiWindowIndex, GuiControlIndex; // The GUI window index and control index that launched this thread.
GuiIndexType GuiDefaultWindowIndex; // This thread's default GUI window, used except when specified "Gui, 2:Add, ..."
GuiIndexType DialogOwnerIndex; // This thread's GUI owner, if any. Stored as Index vs. HWND to insulate against the case where a GUI window has been destroyed and recreated with a new HWND.
? g_gui[g.DialogOwnerIndex]->mHwnd : NULL) // Above line relies on short-circuit eval. oder.
int WinDelay; // negative values may be used as special flags.
int ControlDelay; // negative values may be used as special flags.
int KeyDelay; //
int KeyDelayPlay; //
int PressDuration; // The delay between the up-event and down-event of each keystroke.
int PressDurationPlay; //
int MouseDelay; // negative values may be used as special flags.
int MouseDelayPlay; //
char FormatFloat[32];
Func *CurrentFunc; // v1.0.46.16: The function whose body is currently being processed at load-time, or being run at runtime (if any).
Label *CurrentLabel; // The label that is currently awaiting its matching "return" (if any).
HWND hWndLastUsed; // In many cases, it's better to use GetValidLastUsedWindow() when referring to this.
//HWND hWndToRestore;
int MsgBoxResult; // Which button was pressed in the most recent MsgBox.
HWND DialogHWND;
// All these one-byte members are kept adjacent to make the struct smaller, which helps conserve stack space:
SendModes SendMode;
DWORD PeekFrequency; // DWORD vs. UCHAR might improve performance a little since it's checked so often.
DWORD CalledByIsDialogMessageOrDispatchMsg; // Detects that fact that some messages (like WM_KEYDOWN->WM_NOTIFY for UpDown controls) are translated to different message numbers by IsDialogMessage (and maybe Dispatch too).
bool CalledByIsDialogMessageOrDispatch; // Helps avoid launching a monitor function twice for the same message. This would probably be okay if it were a normal global rather than in the g-struct, but due to messaging complexity, this lends peace of mind and robustness.
bool TitleFindFast; // Whether to use the fast mode of searching window text, or the more thorough slow mode.
bool DetectHiddenWindows; // Whether to detect the titles of hidden parent windows.
bool DetectHiddenText; // Whether to detect the text of hidden child windows.
bool AllowThreadToBeInterrupted; // Whether this thread can be interrupted by custom menu items, hotkeys, or timers.
bool AllowTimers; // v1.0.40.01 Whether new timer threads are allowed to start during this thread.
bool ThreadIsCritical; // Whether this thread has been marked (un)interruptible by the "Critical" command.
bool IsPaused, UnderlyingThreadIsPaused; // The latter supports better toggling via "Pause" or "Pause Toggle".
};
inline void global_clear_state(global_struct &g)
// Reset those values that represent the condition or state created by previously executed commands
// but that shouldn't be retained for future threads (e.g. SetTitleMatchMode should be retained for
// future threads if it occurs in the auto-execute section, but ErrorLevel shouldn't).
{
g.CurrentFunc = NULL;
g.CurrentLabel = NULL;
g.hWndLastUsed = NULL;
//g.hWndToRestore = NULL;
g.MsgBoxResult = 0;
g.IsPaused = false;
g.UnderlyingThreadIsPaused = false;
g.UninterruptedLineCount = 0;
g.DialogOwnerIndex = MAX_GUI_WINDOWS; // Initialized to out-of-bounds.
g.CalledByIsDialogMessageOrDispatch = false; // CalledByIsDialogMessageOrDispatchMsg doesn't need to be cleared because it's value is only considered relevant when CalledByIsDialogMessageOrDispatch==true.
g.GuiDefaultWindowIndex = 0;
// Above line is done because allowing it to be permanently changed by the auto-exec section
// seems like it would cause more confusion that it's worth. A change to the global default
// or even an override/always-use-this-window-number mode can be added if there is ever a
// demand for it.
g.mLoopIteration = 0; // Zero seems preferable to 1, to indicate "no loop currently running" when a thread first starts off. This should probably be left unchanged for backward compatibility (even though script's aren't supposed to rely on it).
g.mLoopFile = NULL;
g.mLoopRegItem = NULL;
g.mLoopReadFile = NULL;
g.mLoopField = NULL;
}
inline void global_init(global_struct &g)
// This isn't made a real constructor to avoid the overhead, since there are times when we
// want to declare a local var of type global_struct without having it initialized.
{
// Init struct with application defaults. They're in a struct so that it's easier
// to save and restore their values when one hotkey interrupts another, going into
// deeper recursion. When the interrupting subroutine returns, the former
// subroutine's values for these are restored prior to resuming execution:
global_clear_state(g);
g.SendMode = SM_EVENT; // v1.0.43: Default to SM_EVENT for backward compatibility.
g.TitleMatchMode = FIND_IN_LEADING_PART; // Standard default for AutoIt2 and 3.
g.TitleFindFast = true; // Since it's so much faster in many cases.
g.DetectHiddenWindows = false; // Same as AutoIt2 but unlike AutoIt3; seems like a more intuitive default.
g.DetectHiddenText = true; // Unlike AutoIt, which defaults to false. This setting performs better.
// Not sure what the optimal default is. 1 seems too low (scripts would be very slow by default):
g.LinesPerCycle = -1;
g.IntervalBeforeRest = 10; // sleep for 10ms every 10ms
#define DEFAULT_PEEK_FREQUENCY 5
g.PeekFrequency = DEFAULT_PEEK_FREQUENCY; // v1.0.46. See comments in ACT_CRITICAL.
g.AllowThreadToBeInterrupted = true; // Separate from g_AllowInterruption so that they can have independent values.
g.AllowTimers = true;
g.ThreadIsCritical = false;
#define PRIORITY_MINIMUM INT_MIN
g.Priority = 0;
g.LastError = 0;
g.GuiEvent = GUI_EVENT_NONE;
g.EventInfo = NO_EVENT_INFO;
g.GuiPoint.x = COORD_UNSPECIFIED;
g.GuiPoint.y = COORD_UNSPECIFIED;
// For these, indexes rather than pointers are stored because handles can become invalid during the
// lifetime of a thread (while it's suspended, or if it destroys the control or window that created itself):
g.GuiWindowIndex = MAX_GUI_WINDOWS; // Default them to out-of-bounds.
g.GuiControlIndex = NO_CONTROL_INDEX; //
g.GuiDefaultWindowIndex = 0;
g.WinDelay = 100;
g.ControlDelay = 20;
g.KeyDelay = 10;
g.KeyDelayPlay = -1;
g.PressDuration = -1;
g.PressDurationPlay = -1;
g.MouseDelay = 10;
g.MouseDelayPlay = -1;
#define DEFAULT_MOUSE_SPEED 2
#define MAX_MOUSE_SPEED 100
#define MAX_MOUSE_SPEED_STR "100"
g.DefaultMouseSpeed = DEFAULT_MOUSE_SPEED;
g.CoordMode = 0; // All the flags it contains are off by default.
g.StringCaseSense = SCS_INSENSITIVE; // AutoIt2 default, and it does seem best.
g.StoreCapslockMode = true; // AutoIt2 (and probably 3's) default, and it makes a lot of sense.
g.AutoTrim = true; // AutoIt2's default, and overall the best default in most cases.
strcpy(g.FormatFloat, "%0.6f");
g.FormatIntAsHex = false;
// For FormatFloat:
// I considered storing more than 6 digits to the right of the decimal point (which is the default
// for most Unices and MSVC++ it seems). But going beyond that makes things a little weird for many
// numbers, due to the inherent imprecision of floating point storage. For example, 83648.4 divided
// by 2 shows up as 41824.200000 with 6 digits, but might show up 41824.19999999999700000000 with
// 20 digits. The extra zeros could be chopped off the end easily enough, but even so, going beyond
// 6 digits seems to do more harm than good for the avg. user, overall. A default of 6 is used here
// in case other/future compilers have a different default (for backward compatibility, we want
// 6 to always be in effect as the default for future releases).
}
#define ERRORLEVEL_SAVED_SIZE 128 // The size that can be remembered (saved & restored) if a thread is interrupted. Big in case user put something bigger than a number in g_ErrorLevel.